package com.ma.a20;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * @ClassName A20
 * @Author: mayongqiang
 * @DATE 2022/4/14 19:50
 * @Description:
 */
/*
学到了什么
    a. DispatcherServlet 是在第一次被访问时执行初始化, 也可以通过配置修改为 Tomcat 启动后就初始化
    b. 在初始化时会从 Spring 容器中找一些 Web 需要的组件, 如 HandlerMapping、HandlerAdapter 等

本章介绍两个最为重要的组件
    a. RequestMappingHandlerAdapter, 以 @RequestMapping 作为映射路径
    b. RequestMappingHandlerAdapter, 调用 handler
    c. 控制器的具体方法会被当作 handler
        - handler 的参数和返回值多种多样
        - 需要解析方法参数, 由 HandlerMethodArgumentResolver 来做
        - 需要处理方法返回值, 由 HandlerMethodReturnValueHandler 来做
*/
public class A20 {
    private static final Logger log = LoggerFactory.getLogger(A20.class);

    public static void main(String[] args) throws Exception {
        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        // 作用: 解析@RequestMapping 以及派生注解,生成路径与控制器方法之间的映射关系（初始化该bean时生成）
        RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);

        // 获取映射结果  eg：{请求方式[url路径：具体控制器方法位置} {GET [/test1]} = com.ma.a20.Controller1#test1()
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();
        handlerMethods.forEach((k, v) -> System.out.println(k + " = " + v));

        MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test4");
        //request.addHeader("token", "某个令牌");
        MockHttpServletResponse response = new MockHttpServletResponse();

        // 请求来了,获取控制器方法   返回处理器执行链对象
        HandlerExecutionChain chain = handlerMapping.getHandler(request);
        System.out.println(chain);
        System.out.println("=====================");

        //HandlerAdapter 作用: 调用控制器方法调用handlerMethods
        MyRequestMappingHandlerAdapter handlerAdapter = context.getBean(MyRequestMappingHandlerAdapter.class);
        handlerAdapter.invokeHandlerMethod(request, response, (HandlerMethod) chain.getHandler());

        // 检查响应
        byte[] content = response.getContentAsByteArray();
        System.out.println(new String(content, StandardCharsets.UTF_8));

        //System.out.println("==========所有的参数解析器=============");

        /*for (HandlerMethodArgumentResolver argumentResolver : handlerAdapter.getArgumentResolvers()) {
            System.out.println(argumentResolver);
        }

        System.out.println("==========所有的返回值解析器=============");
        for (HandlerMethodReturnValueHandler returnValueHandler : handlerAdapter.getReturnValueHandlers()) {
            System.out.println(returnValueHandler);
        }*/
    }
}
